15.1 Promise的含义
说明:Promise
是异步编程
的一种解决方案,比传统的解决方案——回调函数和事件,更合理和更强大
缺点:
- 一旦新建它就会立即执行,无法中途取消
- 如果不设置回调函数,
Promise
内部抛出的错误,不会反应到外部 - 当处于
Pending
状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)
扩展:如果某些事件不断地反复发生,一般来说,使用stream模式
是比部署Promise
更好的选择
Promise对象
说明:代表一个异步操作,有3个状态
Pending
:进行中Resolved
: 已完成Regected
: 已失败
特点:两个特点
- 对象的状态不受外界影响
- 一旦状态改变,就不会再变,任何时候都可以得到这个结果
15.2 基本用法
Promise 构造函数
说明:Promise
作为一个构造函数,用来生成Promise
实例
参数 | 类型 | 说明 | 必需 |
---|---|---|---|
resolver |
function |
该函数作为异步操作的处理函数 | 是 |
参数解释:resolver
被调用时会传两个参数进来,它们都是函数
resolver
函数: 调用该函数,将Promise
对象的状态从“未完成”(Pending
)变为“成功”(Resolved
),在异步操作成功时调用,并将异步操作的结果
,作为参数传递出去reject
函数:调用该函数,将Promise
对象的状态从“未完成”(Pending
)变为“失败”(Rejected
),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去
Promise.prototype.then()
说明:可以用then
方法分别指定Resolved
状态和Reject
状态的回调函数
Demo1: 用Promise
对象实现的Ajax
操作
1 | var getJSON = function(url) { |
15.3 Promise.prototype.then()
说明:为Promise
实例添加状态改变时的回调函数
参数 | 类型 | 说明 | 必需 |
---|---|---|---|
1 | function |
Resolved 状态的回调函数 |
否 |
2 | function |
是Rejected 状态的回调函数 |
否 |
返回值:一个新的Promise
实例(注意,不是原来那个Promise
实例)
1 | var getJSON = function(url) { |
15.4 Promise.prototype.catch()
说明:用于指定发生错误时的回调函数,相当于then
只提供rejected
状态的回调(Promise.prototype.then(null, rejection)
)
- 如果
Promise
状态已经变成Resolved
,再抛出错误是无效的 Promise
对象的错误具有冒泡
性质,会一直向后传递(所以链式调用中,位置靠后报错不会被位置靠前的catch
捕获),直到被捕获为止跟传统的
try/catch
代码块不同的是,如果没有使用catch
方法指定错误处理的回调函数,Promise
对象抛出的错误不会传递到外层代码,即不会有任何反应(Chrome浏览器不遵守这条规定,它会抛出错误“ReferenceError: x is not defined”。)catch
方法之中,还能再抛出错误,如果后面还有catch
,可以被捕获
参数 | 类型 | 说明 | 必需 |
---|---|---|---|
1 | function |
发生错误时的回调函数 | 是 |
返回值:一个新的 promise
对象
建议:一般来说,不要在then
方法里面定义Reject
状态的回调函数(即then
的第二个参数),总是使用catch
方法
Demo1: 基本使用
1 | // getJSON方法返回一个Promise对象 |
Demo2: 调用 reject 等同于抛出错误
1 | // 写法一:通过 throw 抛出错误,触发 catch |
Demo3: Promise对象的错误具有“冒泡”性质,会一直向后传递,直到被捕获为止
1 | getJSON("/post/1.json") |
Demo4: catch 中也可以跑出错误
1 | var someAsyncThing = function() { |
15.5 Promise.all()
说明:用于将多个Promise
实例,包装成一个新的Promise
实例,新的Promise
实例的状态和原本的一批Promise
实例的状态之间的关系是
- 只有原本的一批
Promise
实例的状态都变成fulfilled
,新的Promise
实例的状态才会变成fulfilled
,此时原本的一批Promise
实例的返回值组成一个数组,传递给p的回调函数 - 只要原本的一批
Promise
实例之中有一个被rejected
,新的Promise
实例的状态就变成rejected
,此时第一个被reject
的实例的返回值,会传递给新的Promise
实例的回调函数
参数 | 类型 | 说明 | 必需 |
---|---|---|---|
1 | Iterator |
必须具有Iterator 接口,且返回的每个成员都是Promise 实例(如果不是,就会先调用Promise.resolve 方法,将参数转为Promise 实例) |
是 |
返回值:一个新的Promise
实例
Demo1: 基本使用
1 | // 生成一个Promise对象的数组 |
Demo2: 两个异步操作
1 | const databasePromise = connectDatabase(); |
15.6 Promise.race()
说明:用于将多个Promise
实例,包装成一个新的Promise
实例,新的Promise
实例的状态和原本的一批Promise
实例的状态之间的关系是
- 只要原本的一批
Promise
实例之中有一个实例率先改变状态,新的Promise
实例的状态就跟着改变。那个率先改变的Promise
实例的返回值,就传递给新的Promise
实例的回调函数
参数:和Promise.all()
完全一致
Demo: 如果指定时间内没有获得结果,就将Promise的状态变为reject,否则变为resolve
1 | var p = Promise.race([ |
15.7 Promise.resolve()
说明:将现有对象转为Promise
对象(状态不一定就是resolved
)
技巧:如果希望得到一个Promise
对象,比较方便的方法就是直接调用Promise.resolve
方法
参数 | 类型 | 说明 | 必需 |
---|---|---|---|
1 | [Promise/thenable/普通object或基本类型] |
参数分成四种情况,下面详细讨论 | 否 |
情形 | 参数说明 | Promise.resolve() 行为 |
---|---|---|
1) | Promise 实例 |
原封不动地返回这个实例 |
2) | thenable 对象(具有then 方法的对象) |
将这个对象转为Promise 对象 |
3) | 普通object 或基本类型 |
返回一个新的Promise对象,状态为Resolved ,并将该参数传递 |
4) | 没有参数 | 直接返回一个Resolved 状态的Promise 对象 |
注意:情形3)
和4)
中,状态的改变(变为Resolved
)发生在本轮时间循环
结束时
Demo1: 基本使用
1 | Promise.resolve('foo') |
Demo2 情形2
1 | /** |
Demo3: 情形3
1 | var p = Promise.resolve('Hello'); |
Demo4: 情形4
1 | // 插入到下一轮事件循环的开头 |
15.8 Promise.reject()
说明:也会返回一个新的 Promise
实例,该实例的状态为rejected
参数:和Promise.resolved()
完全一致
1 | var p = Promise.reject('出错了'); |
15.9 两个有用的附加方法
说明:不是Promise API
提供的方法,需要自己部署
done()
说明:总是处于回调链的尾端,保证抛出任何可能出现的错误
参数:和Promise.prototype.then()
完全一致
部署
1 | Promise.prototype.done = function (onFulfilled, onRejected) { |
使用
1 | asyncFunc() |
finally()
说明:总是处于回调链的尾端,用于指定不管Promise
对象最后状态如何,都会执行的操作
参数 | 类型 | 说明 | 必需 |
---|---|---|---|
1 | function |
该函数不管怎样都必须执行 | 是 |
部署
1 | Promise.prototype.finally = function (callback) { |
使用:服务器使用Promise处理请求,然后使用finally方法关掉服务器
1 | server.listen(0) |
15.10 应用
加载图片
1 | const preloadImage = function (path) { |
Generator函数与Promise的结合
1 | function getFoo () { |